﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace TuanHA_Monk
{
    public partial class Classname : CombatRoutine
    {
        #region Delegates

        public delegate WoWPoint LocationRetriverDelegate(object context);

        #endregion

        #region Basic Functions

        public override bool WantButton
        {
            get { return true; }
        }

        public override WoWClass Class
        {
            get { return WoWClass.Monk; }
        }

        public override string Name
        {
            get { return "TuanHA Monk The Ultimate Experience [Public Release]"; }
        }

        public override Composite RestBehavior
        {
            get { return RestRotation(); }
        }

        public override Composite PreCombatBuffBehavior
        {
            get { return MainRotation(); }
        }

        //public override Composite PullBuffBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //public override Composite PullBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //public override Composite CombatBuffBehavior
        //{
        //    get { return MainRotation(); }
        //}

        public override Composite CombatBehavior
        {
            get { return MainRotation(); }
        }

        //public override Composite HealBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //public override Composite MoveToTargetBehavior
        //{
        //    get { return CreateMoveToLosBehavior(); }
        //}

        public static LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        public override void Initialize()
        {
            Logging.Write("");
            Logging.Write("Hello " + Me.Race + " " + Me.Class);
            Logging.Write("Thank you for using TuanHA Monk");
            Logging.Write("");

            //Disable for speed
            //Lua.Events.AttachEvent("ACTIVE_TALENT_GROUP_CHANGED", UpdateStatusEvent);
            //Lua.Events.AttachEvent("PLAYER_TALENT_UPDATE", UpdateMyTalentEvent);
            //Lua.Events.AttachEvent("GLYPH_ADDED", UpdateMyGlyphEvent);
            //Lua.Events.AttachEvent("WORLD_MAP_NAME_UPDATE", UpdateCurrentMapEvent);

            //BotEvents.Player.OnMapChanged += UpdateCurrentMapEvent;
            BotEvents.OnBotStarted += OnBotStartedEvent;

            //Set Camera angle so you never have problem with it
            //console cameraSmoothTrackingStyle 0 (credit by alxaw - member of CLU dev team) 
            Lua.DoString("RunMacroText(\"/console cameraSmoothTrackingStyle 0\")");

            THSettings.Instance.UpdateStatus = true;
        }

        public override void OnButtonPress()
        {
            var gui = new THForm();
            gui.ShowDialog();
        }

        #endregion

        #region Function After this Region Order Alphabetically

        #endregion

        #region GetUnits

        internal static IEnumerable<WoWPartyMember> GroupMembers { get { return !Me.GroupInfo.IsInRaid ? Me.GroupInfo.PartyMembers : Me.GroupInfo.RaidMembers; } }

        public List<WoWUnit> AllUnit = new List<WoWUnit>();
        public List<WoWUnit> FarFriendlyPlayers = new List<WoWUnit>();
        public List<WoWUnit> FarFriendlyUnits = new List<WoWUnit>();
        public List<WoWPlayer> NearbyFriendlyPlayers = new List<WoWPlayer>();
        public List<WoWUnit> NearbyFriendlyUnits = new List<WoWUnit>();
        public List<WoWPlayer> NearbyUnFriendlyPlayers = new List<WoWPlayer>();
        public List<WoWUnit> NearbyUnFriendlyUnits = new List<WoWUnit>();

        public void GetUnits()

        {
            AllUnit.Clear();
            NearbyFriendlyPlayers.Clear();
            NearbyUnFriendlyPlayers.Clear();
            NearbyFriendlyUnits.Clear();
            NearbyUnFriendlyUnits.Clear();

            AllUnit.Add(Me);
            NearbyFriendlyUnits.Add(Me);
            NearbyFriendlyPlayers.Add(Me);

            IEnumerable<WoWUnit> units =
                ObjectManager.GetObjectsOfType<WoWUnit>(true, true).Where(
                    p =>
                    (ValidUnit(p) || p.SummonedByUnitGuid == Me.Guid) &&
                    !Blacklist.Contains(p.Guid) &&
                    p.Distance <= 40);

            foreach (WoWUnit unit in units)
            {
                if (IsEnemy(unit))
                {
                    AllUnit.Add(unit);

                    NearbyUnFriendlyUnits.Add(unit);

                    var player = unit as WoWPlayer;
                    if (player != null)
                    {
                        NearbyUnFriendlyPlayers.Add(player);
                    }
                }
                else if (unit != Me && IsMyPartyRaidMember(unit))
                {
                    NearbyFriendlyUnits.Add(unit);
                    var player = unit as WoWPlayer;
                    if (player != null)
                    {
                        NearbyFriendlyPlayers.Add(player);
                    }
                }
            }
        }

        #endregion

        #region GetUnitHeal

        public WoWUnit UnitHeal;

        private void GetUnitHeal()
        {
            UnitHeal = null;

            if (Healable(Me.CurrentTarget) && Me.CurrentTarget != UnitHealFull &&
                Me.CurrentTarget.HealthPercent < THSettings.Instance.SDoNotHealAbove &&
                (Me.CurrentTarget.IsPlayer || Me.CurrentTarget.IsPet))
            {
                UnitHeal = Me.CurrentTarget;
            }
            else if (Me.HealthPercent < THSettings.Instance.SPriorityHeal &&
                     Me != UnitHealFull && !Me.IsFFAPvPFlagged)
            {
                UnitHeal = Me;
            }
            else if (Healable(Me.FocusedUnit) && Me.FocusedUnit != UnitHealFull &&
                     Me.FocusedUnit.HealthPercent < THSettings.Instance.SDoNotHealAbove &&
                     (Me.FocusedUnit.IsPlayer || Me.FocusedUnit.IsPet) && !Me.IsFFAPvPFlagged)
            {
                UnitHeal = Me.FocusedUnit;
            }
            else
            {
                using (StyxWoW.Memory.AcquireFrame())
                {
                    UnitHeal = (from unit in NearbyFriendlyUnits
                                where !Blacklist.Contains(unit.Guid)
                                orderby unit.HealthPercent ascending
                                where unit != UnitHealFull
                                where unit.IsPlayer || Me.CurrentMap.IsArena && (unit.IsPlayer || unit.IsPet)
                                where HealableValid(unit)
                                select unit).FirstOrDefault();
                }
            }
        }

        #endregion

        #region GetUnitAttack

        public WoWUnit UnitAttack;
        public WoWUnit UnitAttackASAP;
        public WoWUnit UnitAttackPet;

        private void GetUnitAttack()
        {
            UnitAttack = null;
            UnitAttackPet = null;
            UnitAttackASAP = null;

            if (UnitAttackASAP == null && THSettings.Instance.SAutoTarget)
            {
                using (StyxWoW.Memory.AcquireFrame())
                {
                    UnitAttack = (from unit in NearbyUnFriendlyUnits
                                  //Only search Target if in instance
                                  //where Me.IsInInstance
                                  orderby unit.Distance ascending
                                  //attack any unit if not in dungeon/raid
                                  where unit.Combat
                                  //where unit.GotTarget
                                  //only attack unit not tagged
                                  where
                                      unit.IsTargetingMeOrPet || unit.IsTargetingMyPartyMember ||
                                      unit.IsTargetingMyRaidMember
                                  where AttackableValid(unit)
                                  select unit).FirstOrDefault();

                    //if it pet, try to find a player
                    if (UnitAttack != null && !UnitAttack.IsPlayer && !Me.CurrentMap.IsRaid && !Me.CurrentMap.IsDungeon)
                    {
                        UnitAttackPet = UnitAttack;
                        UnitAttack = (from unit in NearbyUnFriendlyPlayers
                                      orderby unit.Distance ascending
                                      where unit.Combat && unit.IsTargetingMeOrPet || Me.CurrentMap.IsBattleground
                                      where AttackableValid(unit)
                                      select unit).FirstOrDefault();

                        //can't find a player, kill the pet
                        if (UnitAttack == null && UnitAttackPet != null)
                        {
                            UnitAttack = UnitAttackPet;
                        }
                    }
                }
            }
        }

        #endregion

        #region Hold

        public static string MyCastingSpells = "[Fists of Fury]";

        public Composite Hold()
        {
            return
                new Decorator(
                    ret =>
                    Me.HasAura("Drink") || Me.HasAura("Food") ||
                    Me.IsCasting &&
                    (Me.ChanneledCastingSpellId != 0 ||
                     !MyCastingSpells.Contains(Me.CastingSpell.Name)) ||
                    !Me.IsAlive,
                    new Action(delegate { return RunStatus.Success; })
                    );
        }

        #endregion

        #region Pulse

        public override void Pulse()
        {
            if (THSettings.Instance.UpdateStatus)
            {
                UpdateStatus();
            }
            else
            {
                ObjectManager.Update();
                GetUnits();
                GetUnitHeal();
                StopCastingCheck();
                GetUnitAttack();
            }
        }

        #endregion

        #region TrinketPvPComp

        private Composite TrinketPvPComp()
        {
            return new PrioritySelector(
                new Decorator(
                    ret =>
                    THSettings.Instance.STrinketPvP && DebuffCC(Me) > 3000 &&
                    SpellManager.HasSpell("Every Man for Himself") &&
                    SpellManager.Spells["Every Man for Himself"].CooldownTimeLeft.TotalMilliseconds <= MyLatency,
                    new Action(delegate
                                   {
                                       if (THSettings.Instance.SAutoTarget && Me.CurrentTarget == null &&
                                           ValidUnit(MyLastTarget))
                                       {
                                           MyLastTarget.Target();
                                       }

                                       if (DebuffCCBreakonDamage(Me) > 0 &&
                                           DotAll(Me) > 0)
                                       {
                                           Logging.Write(" - Waiting for Dot / Hand of Sacrifice break it!");
                                       }
                                           //else if (UnitHeal == null || UnitHeal != null &&
                                           //         UnitHeal.HealthPercent > 80)
                                           //{
                                           //    Logging.Write(" - Don't trinket, Everyone still safe!");
                                           //}
                                       else
                                       {
                                           Logging.Write(" - Use: Every Man for Himself");
                                           CastSpell("Every Man for Himself", Me);
                                       }
                                       return RunStatus.Failure;
                                   })),
                new Decorator(
                    ret =>
                    THSettings.Instance.STrinketPvP && DebuffCC(Me) > 3000 &&
                    Me.Inventory.Equipped.Trinket1 != null &&
                    Me.Inventory.Equipped.Trinket1.CooldownTimeLeft.TotalMilliseconds <= MyLatency &&
                    Me.Inventory.Equipped.Trinket1.Name.Contains("Gladiator's Medallion of"),
                    // [Ruthless Gladiator's Emblem of Cruelty]
                    new Action(delegate
                                   {
                                       if (DebuffCCBreakonDamage(Me) > 0 &&
                                           DotAll(Me) > 0)
                                       {
                                           Logging.Write(" - Waiting for Dot / Hand of Sacrifice break it!");
                                       }
                                           //else if (UnitHeal == null || UnitHeal != null &&
                                           //         UnitHeal.HealthPercent > 80)
                                           //{
                                           //    Logging.Write(" - Don't trinket, Everyone still safe!");
                                           //}
                                       else
                                       {
                                           Logging.Write(" - Use: " +
                                                         Me.Inventory.Equipped.Trinket1.Name);
                                           Me.Inventory.Equipped.Trinket1.Use();
                                       }
                                       return RunStatus.Failure;
                                   })),
                new Decorator(
                    ret =>
                    THSettings.Instance.STrinketPvP && DebuffCC(Me) > 3000 &&
                    Me.Inventory.Equipped.Trinket2 != null &&
                    Me.Inventory.Equipped.Trinket2.CooldownTimeLeft.TotalMilliseconds <= MyLatency &&
                    Me.Inventory.Equipped.Trinket2.Name.Contains("Gladiator's Medallion of"),
                    // [Ruthless Gladiator's Emblem of Cruelty]
                    new Action(delegate
                                   {
                                       if (DebuffCCBreakonDamage(Me) > 0 &&
                                           DotAll(Me) > 0)
                                       {
                                           Logging.Write(" - Waiting for Dot / Hand of Sacrifice break it!");
                                       }
                                           //else if (UnitHeal == null || UnitHeal != null &&
                                           //         UnitHeal.HealthPercent > 80)
                                           //{
                                           //    Logging.Write(" - Don't trinket, Everyone still safe!");
                                           //}
                                       else
                                       {
                                           Logging.Write(" - Use: " +
                                                         Me.Inventory.Equipped.Trinket2.Name);
                                           Me.Inventory.Equipped.Trinket2.Use();
                                       }
                                       return RunStatus.Failure;
                                   })),
                new Decorator(ret => DebuffCC(Me) > 0,
                              new Action(delegate
                                             {
                                                 if (THSettings.Instance.SAutoTarget && Me.CurrentTarget == null &&
                                                     ValidUnit(MyLastTarget))
                                                 {
                                                     MyLastTarget.Target();
                                                 }
                                                 return RunStatus.Failure;
                                             }))
                );
        }

        #endregion

        #region GetPhysicDPSTarget

        //public WoWUnit PhysicDPSTarget;

        //private bool GetPhysicDPSTarget(WoWObject target)
        //{
        //    using (StyxWoW.Memory.AcquireFrame())
        //    {
        //        PhysicDPSTarget = null;
        //        if (Me.CurrentMap.IsArena || Me.CurrentMap.IsBattleground)
        //        {
        //            PhysicDPSTarget = (from unit in NearbyUnFriendlyPlayers
        //                               where unit.CurrentTarget == target
        //                               where
        //                                   TalentSort(unit) == 2 && unit.Location.Distance(target.Location) < 40 ||
        //                                   TalentSort(unit) == 1 && unit.Location.Distance(target.Location) < 6
        //                               where DebuffCC(unit) <= 0
        //                               select unit).FirstOrDefault();
        //        }
        //        else
        //        {
        //            PhysicDPSTarget = (from unit in NearbyUnFriendlyUnits
        //                               where unit.CurrentTarget == target
        //                               where unit.Location.Distance(target.Location) < 6
        //                               //Make sure it melee
        //                               where DebuffCC(unit) <= 0
        //                               select unit).FirstOrDefault();
        //        }
        //        return PhysicDPSTarget != null;
        //    }
        //}

        #endregion

        #region MainRotation

        public bool HelloFriend = false;
        public bool IsConstantFace;
        public bool IsOverrideModeOn = false;
        public WoWUnit MyLastTarget;
        public DateTime Now = DateTime.Now;
        public Stopwatch PendingSpellStopWatch = new Stopwatch();
        public DateTime TickMilisecond;
        public DateTime TickMilisecondTotal;
        public WoWUnit UnitHealFull;

        public Composite MainRotation()
        {
            return new PrioritySelector(
                new Decorator(ret => THSettings.Instance.UpdateStatus,
                              new Action(delegate
                                             {
                                                 //Logging.Write("Need Update Status first");
                                                 //UpdateStatus();
                                                 return RunStatus.Success;
                                             })),
                new Decorator(ret => (!StyxWoW.IsInGame || !StyxWoW.IsInWorld || !Me.IsValid),
                              new Action(delegate
                                             {
                                                 THSettings.Instance.UpdateStatus = true;
                                                 Logging.Write(LogLevel.Diagnostic, "Error, Skip Main Rotation.");
                                                 return RunStatus.Success;
                                             })),
                new Action(delegate
                               {
                                   if (Me.IsInInstance && EventHandlers.CombatLogAttached)
                                   {
                                       EventHandlers.DetachCombatLogEvent();
                                       //Logging.Write(LogLevel.Diagnostic, "DetachCombatLogEvent");
                                   }

                                   if (!Me.IsInInstance && !EventHandlers.CombatLogAttached)
                                   {
                                       EventHandlers.AttachCombatLogEvent();
                                       //Logging.Write(LogLevel.Diagnostic, "AttachCombatLogEvent");
                                   }

                                   if (!IsOverrideModeOn &&
                                       //Do not stop movement in LazyRaider if SMoveToTarget enabled
                                       //TreeRoot.Current.Name != "LazyRaider" &&
                                       (GetAsyncKeyState(Keys.LButton) != 0 &&
                                        GetAsyncKeyState(Keys.RButton) != 0) ||
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SStrafleLeft)) != 0 &&
                                       IndexToKeys(THSettings.Instance.SStrafleLeft) != Keys.None ||
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SForward)) != 0 &&
                                       IndexToKeys(THSettings.Instance.SForward) != Keys.None ||
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SStrafleRight)) != 0 &&
                                       IndexToKeys(THSettings.Instance.SStrafleRight) != Keys.None ||
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.STurnLeft)) != 0 &&
                                       IndexToKeys(THSettings.Instance.STurnLeft) != Keys.None ||
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SBackward)) != 0 &&
                                       IndexToKeys(THSettings.Instance.SBackward) != Keys.None ||
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.STurnRight)) != 0 &&
                                       IndexToKeys(THSettings.Instance.STurnRight) != Keys.None)
                                   {
                                       //Logging.Write(LogLevel.Diagnostic, "Override mode on. Stop all bot movement");
                                       IsOverrideModeOn = true;
                                   }

                                   if (IsOverrideModeOn &&
                                       //Do not stop movement in LazyRaider if SMoveToTarget enabled
                                       //TreeRoot.Current.Name != "LazyRaider" &&
                                       GetAsyncKeyState(Keys.LButton) == 0 &&
                                       GetAsyncKeyState(Keys.RButton) == 0 &&
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SStrafleLeft)) == 0 &&
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SForward)) == 0 &&
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SStrafleRight)) == 0 &&
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.STurnLeft)) == 0 &&
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.SBackward)) == 0 &&
                                       GetAsyncKeyState(IndexToKeys(THSettings.Instance.STurnRight)) == 0)
                                   {
                                       //Logging.Write(LogLevel.Diagnostic, "Override mode off. Bot movement resume");
                                       IsOverrideModeOn = false;
                                   }

                                   if (GetAsyncKeyState(Keys.F9) != 0)
                                   {
                                       Logging.Write("MainRotation take " +
                                                     Math.Round((DateTime.Now -
                                                                 TickMilisecondTotal).TotalMilliseconds) +
                                                     " ms");
                                       TickMilisecondTotal = DateTime.Now;
                                   }

                                   //GetAllMyAuras
                                   if (GetAsyncKeyState(Keys.F10) != 0)
                                   {
                                       DumpAuras();
                                   }

                                   //Get target back after a fear
                                   if (Me.CurrentTarget != null && MyLastTarget != Me.CurrentTarget)
                                   {
                                       MyLastTarget = Me.CurrentTarget;
                                   }

                                   //Clear Target if dead and still in combat
                                   if (Me.CurrentTarget != null && !Me.CurrentTarget.IsAlive && Me.Combat)
                                   {
                                       Lua.DoString("RunMacroText(\"/cleartarget\")");
                                   }

                                   //Clear Target if walk away from friendly
                                   if (Me.CurrentTarget != null && !Me.CurrentTarget.IsPlayer &&
                                       Me.CurrentTarget.IsFriendly &&
                                       Me.CurrentTarget.IsSafelyBehind(Me))
                                   {
                                       Lua.DoString("RunMacroText(\"/cleartarget\")");
                                   }

                                   //Stop PendingSpellStopWatch if no pending spell
                                   if (
                                       PendingSpellStopWatch.IsRunning &&
                                       !Me.HasPendingSpell("Dizzying Haze") &&
                                       !Me.HasPendingSpell("Healing Sphere") &&
                                       !Me.HasPendingSpell("Summon Jade Serpent Statue") &&
                                       !Me.HasPendingSpell("Summon Black Ox Statue"))
                                   {
                                       PendingSpellStopWatch.Stop();
                                       Logging.Write(LogLevel.Diagnostic,
                                                     DateTime.Now.ToString("ss:fff ") +
                                                     "Stop PendingSpellStopWatch, there's no HasPendingSpell");
                                   }

                                   //Auto remove pending spell if it there wait time is more than 1000 ms
                                   if ((Me.HasPendingSpell("Dizzying Haze") ||
                                        Me.HasPendingSpell("Healing Sphere") ||
                                        Me.HasPendingSpell("Summon Jade Serpent Statue") ||
                                        Me.HasPendingSpell("Summon Black Ox Statue")) &&
                                       PendingSpellStopWatch.IsRunning &&
                                       PendingSpellStopWatch.Elapsed.TotalMilliseconds > THSettings.Instance.SPending)
                                   {
                                       PendingSpellStopWatch.Stop();
                                       Logging.Write(LogLevel.Diagnostic,
                                                     DateTime.Now.ToString("ss:fff ") +
                                                     "Remove HasPendingSpell After " +
                                                     PendingSpellStopWatch.Elapsed.TotalMilliseconds + "ms");
                                       Lua.DoString("RunMacroText(\"/use 1\")");
                                   }

                                   //Hold rotation if have pending spell and PendingSpellStopWatch is not running
                                   if ((Me.HasPendingSpell("Dizzying Haze") ||
                                        Me.HasPendingSpell("Healing Sphere") ||
                                        Me.HasPendingSpell("Summon Jade Serpent Statue") ||
                                        Me.HasPendingSpell("Summon Black Ox Statue")) &&
                                       !PendingSpellStopWatch.IsRunning)
                                   {
                                       PendingSpellStopWatch.Reset();
                                       PendingSpellStopWatch.Start();
                                       Logging.Write(LogLevel.Diagnostic,
                                                     DateTime.Now.ToString("ss:fff ") +
                                                     "Hold HasPendingSpell if cast by user");
                                       return RunStatus.Success;
                                   }

                                   //Hold rotation on Zen Meditation
                                   if (Me.IsChanneling && Me.ChanneledCastingSpellId == 115176)
                                   {
                                       Logging.Write(LogLevel.Diagnostic,
                                                     DateTime.Now.ToString("ss:fff ") +
                                                     "Hold All Action On Zen Meditation");
                                       return RunStatus.Success;
                                   }

                                   //Death Knight Dark Simulacrum
                                   //if (Me.HasAura("Dark Simulacrum"))
                                   //{
                                   //    CastSpell("Seal of Insight", Me);
                                   //    return RunStatus.Success;
                                   //}

                                   return RunStatus.Failure;
                               }
                    ),
                SetAutoAttack(),
                TrinketPvPComp(),
                new Decorator(
                    ret =>
                    SpellManager.HasSpell("Stance of the Sturdy Ox"),
                    BrewmasterRotation()
                    ),
                new Decorator(
                    ret =>
                    SpellManager.HasSpell("Stance of the Wise Serpent"),
                    MistweaverRotation()
                    ),
                new Decorator(
                    ret =>
                    !SpellManager.HasSpell("Stance of the Sturdy Ox") &&
                    !SpellManager.HasSpell("Stance of the Wise Serpent"),
                    WindwalkerRotation()
                    )
                );
        }

        #endregion
    }
}